<template>
  <div class="repeat-scroll-outside">
    <slot v-if="list && list.length" name="default"></slot>
    <div v-else-if="showEmptyText && isFinished" class="repeat-scroll-outside--empty-text q-my-md">
      <NoData :text="emptyText" />
    </div>
    <div v-if="isLoading" class="row justify-center q-my-md">
      <t-spinner-dots color="primary" size="40px" />
    </div>
    <div class="repeat-scroll-outside--trigger" ref="triggerRef"></div>
  </div>
</template>

<script setup>
import { ref, onMounted, onBeforeUnmount } from 'vue';
import NoData from '../no-data.vue';

const triggerRef = ref(null);
const observer = ref(null);

const props = defineProps({
  list: {
    type: Array,
    default: () => [],
  },
  showEmptyText: {
    type: Boolean,
    default: true,
  },
  emptyText: {
    type: String,
    default: '暂无数据',
  },
  preloadOffset: {
    type: Number,
    default: 200,
  },
  autoLoad: {
    type: Boolean,
    default: false,
  },
  pageSize: {
    type: Number,
    default: 10,
  }
})

const currentPage = ref(1);
const isFinished = ref(false);
const isLoading = ref(false);

const emit = defineEmits(['scroll-load']);

const findScrollParent = (el) => {
  if (!el) return document.documentElement;

  let parent = el.parentElement;
  while (parent) {
    const { overflow, overflowY } = window.getComputedStyle(parent);
    if (/(auto|scroll)/.test(overflow + overflowY)) {
      return parent;
    }
    parent = parent.parentElement;
  }
  return document.documentElement;
};

const initObserver = () => {
  const scrollParent = findScrollParent(triggerRef.value);
  let offset = 200;
  try {
    offset = parseInt(props.preloadOffset);
  } catch (error) {
    console.log('preloadOffset 不是数字', props.preloadOffset, error);
  }

  observer.value = new IntersectionObserver((entries) => {
    entries.forEach(entry => {
      if (entry.isIntersecting) {
        if (isLoading.value) return;
        isLoading.value = true;
        emit('scroll-load', currentPage.value, (isAllLoaded) => {
          currentPage.value++;
          isLoading.value = false;
          if (isAllLoaded) {
            observer.value.disconnect();
          }
          isFinished.value = isAllLoaded;
        });
      }
    });
  }, {
    root: scrollParent,
    rootMargin: `0px 0px ${offset}px 0px` // 提前100px触发
  });

  if (triggerRef.value) {
    observer.value.observe(triggerRef.value);
  }
};

const reload = () => {
  currentPage.value = 1;
  if (observer.value) {
    observer.value.disconnect();
    observer.value = null;
  }
  initObserver();
};

onMounted(() => {
  if (props.autoLoad) {
    initObserver();
  }
});

onBeforeUnmount(() => {
  if (observer.value) {
    observer.value.disconnect();
  }
});

defineExpose({
  reload
});
</script>

<style>
.repeat-scroll-outside--trigger {
  height:4px;
}
</style>
